//!\mainpage <a href="http://www.lib9.net">www.lib9.net</a>
///Lib9是一套简单易学功能强大的游戏引擎，它的核心思想是程序就是一个状态机，程序的每个部分都是一个状态！
#ifndef _LIB9_H_
#define _LIB9_H_

#include <FBase.h>
#include <FUi.h>
#include <FGraphics.h>
#include <FSystem.h>
#include <FApp.h>
#include "L9IState.h"
#include "L9Config.h"
#include "L9Rect.h"
#include "L9Str.h"
#include "L9DialogMsg.h"
#include "L9DialogYesNo.h"
#include "L9Log.h"
#include <stack>
using namespace Osp::Base;
using namespace Osp::Base::Utility;
using namespace Osp::Base::Runtime;
using namespace Osp::Graphics;
using namespace Osp::System;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;
using namespace Osp::App;
using namespace std;
namespace lib9bada {
///////////////////logic key value////////////////////////////////////////
/*static*/const long long K_KEY_INVALID = -1;
/*static*/const long long K_KEY_0 = ((1LL) << 0);// 数字键
/*static*/
const long long K_KEY_1 = ((1LL) << 1);
/*static*/const long long K_KEY_2 = ((1LL) << 2);
/*static*/const long long K_KEY_3 = ((1LL) << 3);
/*static*/const long long K_KEY_4 = ((1LL) << 4);
/*static*/const long long K_KEY_5 = ((1LL) << 5);
/*static*/const long long K_KEY_6 = ((1LL) << 6);
/*static*/const long long K_KEY_7 = ((1LL) << 7);
/*static*/const long long K_KEY_8 = ((1LL) << 8);
/*static*/const long long K_KEY_9 = ((1LL) << 9);
/*static*/const long long K_KEY_A = ((1LL) << 10);// 字母键
/*static*/
const long long K_KEY_B = ((1LL) << 11);
/*static*/const long long K_KEY_C = ((1LL) << 12);
/*static*/const long long K_KEY_D = ((1LL) << 13);
/*static*/const long long K_KEY_E = ((1LL) << 14);
/*static*/const long long K_KEY_F = ((1LL) << 15);
/*static*/const long long K_KEY_G = ((1LL) << 16);
/*static*/const long long K_KEY_H = ((1LL) << 17);
/*static*/const long long K_KEY_I = ((1LL) << 18);
/*static*/const long long K_KEY_J = ((1LL) << 19);
/*static*/const long long K_KEY_K = ((1LL) << 20);
/*static*/const long long K_KEY_L = ((1LL) << 21);
/*static*/const long long K_KEY_M = ((1LL) << 22);
/*static*/const long long K_KEY_N = ((1LL) << 23);
/*static*/const long long K_KEY_O = ((1LL) << 24);
/*static*/const long long K_KEY_P = ((1LL) << 25);
/*static*/const long long K_KEY_Q = ((1LL) << 26);
/*static*/const long long K_KEY_R = ((1LL) << 27);
/*static*/const long long K_KEY_S = ((1LL) << 28);
/*static*/const long long K_KEY_T = ((1LL) << 29);
/*static*/const long long K_KEY_U = ((1LL) << 30);
/*static*/const long long K_KEY_V = ((1LL) << 31);
/*static*/const long long K_KEY_W = ((1LL) << 32);
/*static*/const long long K_KEY_X = ((1LL) << 33);
/*static*/const long long K_KEY_Y = ((1LL) << 34);
/*static*/const long long K_KEY_Z = ((1LL) << 35);
/*static*/const long long K_KEY_UP = ((1LL) << 36);// D键盘
/*static*/
const long long K_KEY_DOWN = ((1LL) << 37);
/*static*/const long long K_KEY_LEFT = ((1LL) << 38);
/*static*/const long long K_KEY_RIGHT = ((1LL) << 39);
/*static*/const long long K_KEY_OK = ((1LL) << 40);

/*static*/const long long K_KEY_SIDE_UP = ((1LL) << 41);
/*static*/const long long K_KEY_SIDE_DOWN = ((1LL) << 42);
/*static*/const long long K_KEY_CLEAR = ((1LL) << 43);
/*static*/const long long K_KEY_CAMERA = ((1LL) << 44);
/*static*/const long long K_KEY_SWITCH = ((1LL) << 45);
/*static*/const long long K_KEY_ASTERISK = ((1LL) << 46);
/*static*/const long long K_KEY_SHARP = ((1LL) << 47);
/*static*/const long long K_KEY_BACKSPACE = ((1LL) << 48);
/*static*/const long long K_KEY_COMMA = ((1LL) << 49);
/*static*/const long long K_KEY_ENTER = ((1LL) << 50);
/*static*/const long long K_KEY_CAPSLOCK = ((1LL) << 51);
/*static*/const long long K_KEY_QUESTION = ((1LL) << 52);
/*static*/const long long K_KEY_ALT = ((1LL) << 53);
/*static*/const long long K_KEY_SYM = ((1LL) << 54);
/*static*/const long long K_KEY_SETTING = ((1LL) << 55);
/*static*/const long long K_KEY_SPACE = ((1LL) << 56);
/*static*/const long long K_KEY_DOT = ((1LL) << 57);
/*static*/const int nKEY_NUM = 58;
class Lib9: public Osp::Ui::Controls::Form,
		public Osp::Ui::IKeyEventListener,
		public Osp::Ui::ITouchEventListener,
		public IRunnable {
private:

	/*普通的函数访问static变量居然会有问题，标准C++中是应该可以访问的,bada这里访问编译不出错，但是运行有问题，不知道是不是因为线程的原因还是什么原因*/
	/*static*/
	long long keyPressed;
	/*static*/
	long long keyReleased;
	/*static*/
	long long keyState;
	/*static*/
	long long curKeyPressed;
	/*static*/
	long long curKeyReleased;
	/*static*/
	long long curKeyState;

	int pointerX;// = -1;
	int pointerY;// = -1;
	int curPointerX;
	int curPointerY;
	int dragPointerX;// = -1;
	int dragPointerY;// = -1;

	int _keyCode;// = -1;


	bool bFirstInitState;// = false;
	//	Bitmap* imgBuffer;// = null;
	bool bAppInPainting;// = false;
	bool bUseGlobalGraphics;// = false;
	stack<L9IState*> sState;// = new Stack();


	long long lastFrameTime;
	bool bInterruptNotify;
	long long m_lBeginTime;
	long long m_l_DT;
	long long m_frameRate;
	long _fps;// = 15;

	void defaultInit();
	long long System_currentTimeMillis();
	// Construction
public:
	Lib9(Application* pApp);
	virtual ~Lib9(void);
//	bool Initialize(void);
	/**
	 * 图形对象，用来显示程序的画面
	 */
	Canvas* pFG;// = null;

	Font* pFont;
	L9Str* pL9Str;
	/**
	 * 程序的当前状态,就是实现了L9IState接口的对象
	 */
	L9IState* pAppState;
	/**
	 * 程序的主线程是否处理暂停的状态，处于中断中或者需要进入以用户交互的界面中往往需要设置为true
	 */
	bool bAppPaused;
	/**
	 * 屏幕的宽
	 */
	int SCR_W;
	/**
	 * 屏幕的高
	 */
	int SCR_H;
	/**
	 * 帧计数,每一帧都回增加1,在以帧驱动的应用(常常是游戏)中非常有用
	 */
	int frameCount;// = 0;

	/**
	 * 程序对象，可以通过这个对象获取或者设置程序层面的信息
	 */
	/*static*/
	Application* pApp;
	/**
	 * 应用程序的显示容器，程序所绘制的将在该对象上显示
	 */
	/*static*/
	Form* pAppDisplay;
	/**
	 * 应用程序在切换显示容器时，先保存当前的显示容器，这样便于以后返回到上一个显示容器
	 */
	/*static*/
	Form* pLastAppDisplay;
	/**
	 * 系统自带的对话框对象
	 */
	L9DialogMsg* pDialogMsg;
	/**
	 * 系统自带的是否确认对话框
	 */
	L9DialogYesNo* pDialogYesNo;
	// Implementation
protected:

public:
	virtual result OnInitializing(void);
	virtual result OnTerminating(void);

	virtual void OnKeyLongPressed(const Osp::Ui::Control &source,
			Osp::Ui::KeyCode keyCode);
	virtual void OnKeyPressed(const Osp::Ui::Control &source,
			Osp::Ui::KeyCode keyCode);
	virtual void OnKeyReleased(const Osp::Ui::Control &source,
			Osp::Ui::KeyCode keyCode);
	virtual void OnTouchDoublePressed(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchFocusIn(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchFocusOut(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchLongPressed(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchMoved(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchPressed(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchReleased(const Osp::Ui::Control &source,
			const Osp::Graphics::Point &currentPosition,
			const Osp::Ui::TouchEventInfo &touchInfo);

	/////////////////////////////////////////按键系统//////////////////////////////////////////////////////////


	/**
	 * 调用该函数用来模拟按键效果，使用传统按键系统的游戏移动到触摸屏中为了减少工作量常常需要模拟按键效果
	 * @param keyCode int
	 */
	void logicKeyPressed(int keyCode);
	/**
	 * 在帧驱动的应用或者游戏(帧驱动的方式往往是游戏)中每一帧都要清除按键值，isKeyPressed,isKeyReleased将会受到影响,而isKeyUp,isKeyDown则需要手动
	 * 调用
	 */
	void updateKey();

	/**
	 * 清除按键值
	 */
	void resetKey();

	/**
	 * 判断某个键是否已经被释放了，注意参数是逻辑键值，这个函数与isKeyReleased的区别在于在应用程序的每一帧isKeyPressed对应的键值都会被清除，
	 * 而isKeyDown则必须使用ResetKey或者ResetAKey进行清除
	 * @param logicKey int
	 * @return bool
	 */
	bool isKeyDown(long long logicKey);

	/**
	 * 判断某个键是否已经被按下了，注意参数是逻辑键值，这个函数与isKeyPressed的区别在于在应用程序的每一帧isKeyPressed对应的键值都会被清除，
	 * 而isKeyUp则必须使用ResetKey或者ResetAKey进行清除
	 * @param logicKey int
	 * @return bool
	 */
	bool isKeyUp(long long logicKey);

	/**
	 * 判断是否按下了键
	 * @return bool
	 */
	bool isAnyKeyPressed();

	/**
	 * 判断是否有键被释放了
	 * @return int
	 */
	bool isAnyKeyReleased();

	/**
	 * 判断某个键是否已经被按下了，注意参数是逻辑键值
	 * @param logicKey int
	 * @return bool
	 */
	bool isKeyPressed(long long logicKey);

	/**
	 * 判断某个键是否被释放了，注意参数是逻辑键值
	 * @param logicKey int
	 * @return bool
	 */
	bool isKeyReleased(long long logicKey);

	/**
	 * 根据键值返回键的逻辑值
	 * @param keyCode int
	 * @return int
	 */
	long long getLogicKeyByKeyCode(int keyCode);
	/**
	 * 根据逻辑键返回按键值
	 * @param logicKey int
	 * @return int
	 */
	int getKeyCodeByLogicKey(long long logicKey);

	/**
	 * 判断是否处于拖动状态
	 * @return bool
	 */
	bool isDragPointer();

	/**
	 * 返回触摸点的X坐标
	 * @return int
	 */
	int getPointerX();

	/**
	 * 返回触摸点的Y坐标
	 * @return int
	 */
	int getPointerY();

	/**
	 * 在处于拖动状态的时候返回当前点的X坐标
	 * @return int
	 */
	int getDragPointerX();

	/**
	 * 在处于拖动状态的时候返回当前点的Y坐标
	 * @return int
	 */
	int getDragPointerY();
	/**
	 * 返回帧时间,单位微妙
	 *
	 * @return
	 */
	long long getTicks();
	/**
	 * 重载Run方法实现多线程的方式来构建游戏的主循环
	 */
	virtual Object* Run();
	virtual bool OnStart(void);
	virtual void OnStop(void);
	/**
	 * 重载OnDraw方法绘制游戏画面
	 */
	virtual result OnDraw(void);

	//////////////////////////State Manager//////////////////////////////////////////////
	/**
	 * 将状态机的当前状态入栈
	 */
	void pushState();

	/**
	 * 将状态state入栈
	 * @param state L9IState
	 */
	void pushState(L9IState* state);

	/**
	 * 将状态出栈，返回出栈的状态,如果堆栈为空将返回null
	 * @return L9IState
	 */
	L9IState* popState();

	/**
	 * 返回出栈的状态,但是不出栈,如果堆栈为空将返回null
	 * @return L9IState
	 */
	L9IState* topState();

	/**
	 * 返回状态堆栈的大小
	 * @return int
	 */
	int getStateSize();

	/**
	 * 清空状态机堆栈
	 */
	void clearState();

	/**
	 * 用来切换状态机的状态,如果state为null,将退出程序
	 * @param state L9IState
	 */
	void changeState(L9IState* state);

	/**
	 * 必须实现的抽象类方法，用来执行应用的程序逻辑
	 */
	void appUpdate();

	/**
	 * 必须实现的抽象类方法，绘制应用的画面
	 */
	void appPaint();

	/**
	 * 设置程序的fps,就是每秒钟显示的帧数
	 * @param fps int
	 */
	void setFps(int fps);

	/**
	 * 设置程序和设置程序的显示容器
	 * @param app MIDlet
	 * @param disp Displayable
	 */
	void setDisplay(Application* app, Form* disp);
	/**
	 * 切换到上一次的显示容器，调用setDisplay设置显示容器的时候将会记录上一次显示容器，调用backLastDisplay返回上一次显示容器后会将lastAppDisplay=null
	 */
	void backLastDisplay();
	/**
	 * 在使用双缓冲(即L9Config::bUseDoubleBuffer为true)的情况下，使用全局的Graphics
	 * @param bUse bool
	 */
	void setGlobalGraphics(bool bUse);

	/**
	 * 在使用双缓冲(即L9Config::bUseDoubleBuffer为true)且使用全局的Graphics的情况下用来绘制缓存图片的内容
	 */
	void drawBufferImage();
	/**
	 * 清屏操作，用color颜色值来填充指定大小的屏幕
	 */
	void fillScreen(int color, int x, int y, int w, int h);
	/**
	 * 清屏操作，用color颜色值来填充整个屏幕
	 * @param color int
	 */
	void fillScreen(int color);
	/**
	 * 进行界面的绘制操作
	 */
	void paint(Canvas& g);
	/**
	 * 判断某点是否在某个线段之间
	 * @param pX int
	 * @param leftX int
	 * @param rightX int
	 * @return bool
	 */
	bool isInLine(int pX, int leftX, int rightX);

	/**
	 * 判断某个点是否在矩形中，参数rect表示矩形的左上角和右下角两点坐标
	 * @param pX int
	 * @param pY int
	 * @param rect int[]
	 * @return bool
	 */
	bool isInRect(int pX, int pY, L9Rect rect);
	//////////////////////////////////////////////消息对话框/////////////////////////////////////////////////////////////
	/**
	 * 显示消息对话框，默认居中显示，如果是触摸屏的话，可支持拖动
	 * @param sTitle String
	 * @param strMsg String
	 * @param btnText String
	 * @param Dialog_W int
	 */
	void showMsgDialog(String sTitle, String strMsg, String btnText,
			int Dialog_W);

	/**
	 * 显示确认对话框，默认居中显示，如果是触摸屏的话，可支持拖动
	 * @param sTitle String
	 * @param strMsg String
	 * @param sYes String
	 * @param sNo String
	 * @param Dialog_W int
	 */
	void showYesNoDialog(String sTitle, String strMsg, String sYes, String sNo,
			int Dialog_W);
	/**
	 * 退出程序
	 */
	void quitApp();
};
};

#endif	//_LIB9_H_
